iT邦幫忙

2024 iThome 鐵人賽

DAY 18
1
自我挑戰組

Linux Kernel 網路巡禮系列 第 18 篇

記憶體管理 (3) - Segmentation 機制

  • 分享至 

  • xImage
  •  

根據 Intel 手冊,在 64 位元模式下,Segmentation 機制通常是直接穿透的。這意味著,透過 Segmentation 機制的設定,所有邏輯地址會直接一對一對應到線性地址(也稱為 Flat Model),Segmentation 並沒有產生任何地址轉換。

Segmentation 機制運作

在 Intel CPU 架構上,當我們討論虛擬記憶體地址時,指的是邏輯地址中的一部分。這個邏輯地址首先需要經過 Segmentation 機制轉換為線性地址,之後再經由分頁機制轉換為物理地址。

https://ithelp.ithome.com.tw/upload/images/20241002/20152703gcqGwzVRCG.png

在 Segmentation 機制中,邏輯地址由兩個部分組成:segment selector 和 offset(也稱為有效地址 effective address)。我們日常討論的虛擬地址實際上指的是這個 offset,而 segment selector 則是一個保存在 CPU 暫存器中的數值。

https://ithelp.ithome.com.tw/upload/images/20241002/20152703zxiShNZ8xw.png

segment selector 由三個欄位組成:Index、Table Indicator (TI) 和 Requested Privilege Level (RPL)。

我們先解釋 index,index 是 Descriptor Table 的索引值。當 MMU 執行 Segmentation 轉換時,會讀取 segment selector 暫存器,然後透過 Index 找到對應的 Descriptor Table 內的 Entry。

Descriptor Table 中的 Entry 稱為 segment descriptor

https://ithelp.ithome.com.tw/upload/images/20241002/2015270355bDhmaoz1.png

segment descriptor 中,有一個 base address 欄位,MMU 執行地址轉換時,會將這個欄位會與有效地址(offset)相加,從而得到線性地址。這樣就完成了 Segmentation 機制的地址轉換。

另外,還有一個 limit 欄位,用來表示該段的大小。與分頁機制中固定 4K 的頁面大小不同,Segmentation 機制允許每個段的大小由 segment descriptor 定義,因此可以避免程式存取超出範圍。

那這裡就會引生出兩個問題:

  • segment selector 是哪個暫存器?
  • descriptor table 的位置在哪裡?

Segment Selector 暫存器

實際上,segment selector 並不是單一的暫存器,而是有多個暫存器,包括:code-segment (CS)、data-segment (DS)、stack-segment (SS),以及額外的資料段暫存器(ES、FS、GS)。

為什麼會有這麼多不同的 segment selector 暫存器?原因在於它們對應到程式中不同的區段,例如程式碼段(Code)、堆疊(Stack)、資料段(Data)等。CPU 在執行不同功能時,會使用對應的段選擇器。比如,在執行指令抓取(instruction fetch)時,會使用 CS 段選擇器;而在進行一般資料讀寫時,則會使用 DS。

https://ithelp.ithome.com.tw/upload/images/20241002/201527035NyIgQrkw1.png

因此,當我們討論一個 Process 的程式碼、堆疊(Stack)、堆積(Heap)、資料段等區塊在虛擬記憶體中的排列結構時,這些區塊經過 Segmentation 機制後,在線性地址空間中的排列方式可能會完全不同。需要注意的是,這裡指的是線性地址空間中的排列方式,至於最終如何映射到物理記憶體,還需要經過分頁機制。

Descriptor Table 的位置

當 MMU 讀取到 segment selector 中保存的 index 後,會去查找 Descriptor Table。MMU 需要從記憶體中讀取這張表。對於一個 Process 而言,MMU 實際上會看到兩張表:Global Descriptor Table (GDT) 和 Local Descriptor Table (LDT)。

在一個作業系統中,系統會有一張 GDT,並且可能會有多張或無 LDT。GDT 是整個系統共用的,而 LDT 則可能是某個 Process 專用的。在 Intel CPU 中,Global Descriptor Table Register (GDTR) 和 Local Descriptor Table Register (LDTR) 會分別指向 GDT 和 LDT 的位置,MMU 可以透過這兩個暫存器找到 GDT 和 LDT。當 Process 切換時,系統會更新 LDTR 來切換 LDT。在某些情況下,作業系統可以不使用 LDT,所有 Process 和程式碼都使用 GDT。因為還有分頁機制來提供記憶體隔離,這樣的設計是可行的。

MMU 如何知道應該查找哪一張表呢?這與 segment selector 中的 Table Indicator (TI) 欄位有關。當 TI 欄位為 0 時,表示 MMU 應查找 GDT;當為 1 時,則使用 LDT。

分段分頁總整理

https://ithelp.ithome.com.tw/upload/images/20241002/20152703L1JSdRkaMe.png

當 MMU 接收到一個邏輯地址空間的有效地址查詢請求後,會依序執行以下步驟:

  1. 根據指令類型,取得對應的 segment selector 數值。
  2. 根據 segment selector 的 Table Indicator 欄位,判定是使用 GDT 還是 LDT(假設是 GDT)。
  3. 透過 GDTR 取得 GDT 在線性空間中的起始地址。
  4. 根據 segment selector 的 Index,找到對應的 segment descriptor。
  5. 將有效地址加上 segment base address,取得目標線性地址。
  6. 根據線性地址,判定該地址是否已存在於 TLB 中(假設不存在)。
  7. 存取 4-Level Page Table,找到該頁的物理地址起始位置。
  8. 加上線性地址中的 offset 部分,最終取得物理地址。

這就是 Segmentation 與 Paging 機制協同工作的完整流程。


上一篇
記憶體管理 (2) - Paging 機制
下一篇
記憶體管理 (4) - 略過 Segmentation
系列文
Linux Kernel 網路巡禮 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言